﻿/*
 *  Author: Louis A. Leskoviansky
 *  Company: Artemis Solutions Group (http://www.artemis-solutions.com)
 */


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;

namespace AjaxControlFramework
{
    [Serializable]
    public class InternalScriptManager
    {
        //------// Properties \\--------------------------------------------\\
        private Dictionary<string, ScriptReference> _registeredScripts = new Dictionary<string, ScriptReference>();
        public virtual Dictionary<string, ScriptReference> RegisteredScripts
        {
            get { return _registeredScripts; }
        }


        private Dictionary<string, ScriptReference> _renderedScripts = new Dictionary<string, ScriptReference>();
        public virtual Dictionary<string, ScriptReference> RenderedScripts
        {
            get { return _renderedScripts; }
        }


        private List<ScriptReference> _bodyScripts = new List<ScriptReference>();
        public virtual List<ScriptReference> BodyScripts
        {
            get { return _bodyScripts; }
        }


        private List<ScriptReference> _headScripts = new List<ScriptReference>();
        public virtual List<ScriptReference> HeadScripts
        {
            get { return _headScripts; }
        }


        public static InternalScriptManager Instance
        {
            get
            {
                if (HttpContext.Current.Items.Contains("AjaxControl.InternalScriptManager"))
                {
                    return (InternalScriptManager)HttpContext.Current.Items["AjaxControl.InternalScriptManager"];
                }
                else
                {
                    InternalScriptManager scriptManager = new InternalScriptManager();

                    return scriptManager;
                }
            }
        }
        //------\\ Properties //--------------------------------------------//



        //------// Constructors \\------------------------------------------\\
        protected InternalScriptManager()
        {
            HttpContext.Current.Items["AjaxControl.InternalScriptManager"] = this;

            RegisterPreRenderEvent();
        }
        //------\\ Constructors //------------------------------------------//



        //------// Methods \\-----------------------------------------------\\
        protected virtual void RegisterScript_Internal(ScriptReference reference, ScriptRenderLocation renderLocation)
        {
            if (reference == null) { return; }

            if (!RegisteredScripts.ContainsKey(reference.Name))
            {
                RegisteredScripts.Add(reference.Name, reference);

                switch (renderLocation)
                {
                    case ScriptRenderLocation.Body:

                        BodyScripts.Add(reference);
                        break;

                    case ScriptRenderLocation.Head:

                        HeadScripts.Add(reference);
                        break;
                }
            }
        }


        public static void RegisterScript(ScriptReference reference, ScriptRenderLocation renderLocation)
        {
            Instance.RegisterScript_Internal(reference, renderLocation);
        }


        protected virtual void RegisterEmbeddedScript_Internal(string name, string scriptName, string assembly, ScriptRenderLocation renderLocation, bool enabled)
        {
            RegisterScript(new EmbeddedScriptReference(scriptName, scriptName, assembly, enabled), renderLocation);
        }


        public static void RegisterEmbeddedScript(string name, string scriptName, string assembly, ScriptRenderLocation renderLocation, bool enabled)
        {
            Instance.RegisterEmbeddedScript_Internal(name, scriptName, assembly, renderLocation, enabled);
        }


        protected virtual void RegisterEmbeddedScript_Internal(string name, string scriptName, ScriptRenderLocation renderLocation, bool enabled)
        {
            RegisterEmbeddedScript_Internal(name, scriptName, null, renderLocation, enabled);
        }


        public static void RegisterEmbeddedScript(string name, string scriptName, ScriptRenderLocation renderLocation, bool enabled)
        {
            Instance.RegisterEmbeddedScript_Internal(name, scriptName, null, renderLocation, enabled);
        }


        protected virtual void RegisterFileScript_Internal(string name, string sourcePath, ScriptRenderLocation renderLocation, bool enabled)
        {
            RegisterScript(new FileScriptReference(name, sourcePath, enabled), renderLocation);
        }


        public static void RegisterFileScript(string name, string sourcePath, ScriptRenderLocation renderLocation, bool enabled)
        {
            Instance.RegisterFileScript_Internal(name, sourcePath, renderLocation, enabled);
        }


        protected virtual void RegisterInlineScript_Internal(string name, string sourceCode, ScriptRenderLocation renderLocation, bool enabled)
        {
            RegisterScript(new InlineScriptReference(name, sourceCode, enabled), renderLocation);
        }


        public static void RegisterInlineScript(string name, string sourceCode, ScriptRenderLocation renderLocation, bool enabled)
        {
            Instance.RegisterInlineScript_Internal(name, sourceCode, renderLocation, enabled);
        }


        protected virtual void RegisterCompiledScript_Internal(string name, string sourcePath, ScriptRenderLocation renderLocation, ScriptType scriptType, bool enabled)
        {
            RegisterScript(new CompiledScriptReference(name, sourcePath, scriptType, enabled), renderLocation);
        }


        protected virtual void RegisterCompiledScript_Internal(string name, string sourcePath, ScriptRenderLocation renderLocation, ScriptType scriptType, bool enabled, List<string> dependencies)
        {
            CompiledScriptReference compiledScriptReference = new CompiledScriptReference(name, sourcePath, scriptType, enabled);
            compiledScriptReference.Dependencies = dependencies;

            RegisterScript(compiledScriptReference, renderLocation);
        }


        public static void RegisterCompiledScript(string name, string sourcePath, ScriptRenderLocation renderLocation, ScriptType scriptType, bool enabled)
        {
            Instance.RegisterCompiledScript_Internal(name, sourcePath, renderLocation, scriptType, enabled);
        }


        public static void RegisterCompiledScript(string name, string sourcePath, ScriptRenderLocation renderLocation, ScriptType scriptType, bool enabled, List<string> dependencies)
        {
            Instance.RegisterCompiledScript_Internal(name, sourcePath, renderLocation, scriptType, enabled, dependencies);
        }


        protected virtual void RegisterPreRenderEvent()
        {
            Page currentPage = HttpContext.Current.CurrentHandler as Page;

            if (currentPage != null)
            {
                currentPage.PreRender += new EventHandler(delegate(object sender, EventArgs eventArgs) {
                    // Attach to the <body> (if runat="server" has been declared on the <body> element...other attach to the <form>).
                    List<HtmlControl> controls = AjaxControlUtils.FindChildControlsByTagName(AjaxControlUtils.FindTopMostParent(currentPage), "body");

                    HtmlControl bodyOrForm = null;

                    if (controls != null && controls.Count > 0)
                    {
                        bodyOrForm = controls[0];
                    }
                    else
                    {
                        bodyOrForm = currentPage.Form;
                    }

                    if (bodyOrForm != null)
                    {
                        bodyOrForm.PreRender += new EventHandler(delegate(object source, EventArgs args) {
                            RenderingHelper.RenderScriptBlocksAfterControl(BodyScripts, bodyOrForm);
                        });
                    }


                    // Attach to the <head>.
                    if (currentPage.Header != null)
                    {
                        currentPage.Header.PreRender += new EventHandler(delegate(object source, EventArgs args) {
                            RenderingHelper.RenderScriptBlocksAfterControl(HeadScripts, currentPage.Header);
                        });
                    }
                });
            }
        }


        public virtual void AddScriptDependency(string scriptReferenceName, string dependencyScriptName)
        {
            ScriptReference scriptReference = null;
            InternalScriptManager.Instance.RegisteredScripts.TryGetValue(scriptReferenceName, out scriptReference);

            if (scriptReference != null)
            {
                scriptReference.AddDependency(dependencyScriptName);
            }
        }
        //------\\ Methods //-----------------------------------------------//
    }
}
